<?php 
/***
    Amrita ITEWS - Copyright (C) 2009 Amrita Vishwa Vidyapeetham, Amritapuri.
                                     (http://www.amrita.edu)
    ***************************************************************************
    This file is part of the Amrita ITEWS distribution.
    Amrita ITEWS is free software; you can redistribute it and/or modify it 
    under the terms of the GNU General Public License (version 2) as published 
    by the Free Software Foundation AND MODIFIED BY the Amrita ITEWS exception.
    ***NOTE*** The exception to the GPL is included to allow you to distribute
    a combined work that includes Amrita ITEWS without being obliged to provide
    the source code for proprietary components outside of the Amrita ITEWS
    software. Amrita ITEWS is distributed in the hope that it will be useful, 
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    Public License for more details. You should have received a copy of the GNU
    General Public License and the Amrita ITEWS license exception along with 
    Amrita ITEWS if not then it can be viewed here: 
    http://itews.amrita.ac.in/license.html.
    
    Documentation, latest information, license and contact details are at:
    http://itews.amrita.ac.in/
 
    Amrita ITEWS source code can be found at:
    http://code.google.com/p/itews"; 
    
    The initial code-base of Amrita ITEWS was developed by Amrita Vishwa 
    Vidyapeetham as part of the project titled,\"Intelligent & Interactive 
    Telematics using Emerging Wireless Technologies for Transport Systems 
    (ITEWS)\" sponsored by Technology Information Forecasting and Assessment 
    Council (TIFAC), India.
***/
?><?php
class TidInfoController extends AppController {
	
	var $uses = array('LastProcessedTid', 'TelematicUnit', 'Trip', 'TimeSchedule', 'RouteScheduleNodeAssoc', 'RouteSchedule', 'VehicleCurrentNode', 'Configuration', 'ConfigurationParameter');
	var $components = array('TdcsConfigure'); 
	
	function beforeFilter() {
		
		// Set Timezone
		date_default_timezone_set("Asia/Calcutta");
		$this->setAutoIncremetsForModelObjects();
		
	}

    function index() {
    	
		// Because CakePHP loads models in a lazy fashion,
		// it's usually not a good idea to create model instances in components.
		// If you need model data in a component,
		// it's best to pass that data in through one of the component's methods:
		$this->TdcsConfigure->setModel($this->ConfigurationParameter);
		
		$unitTestMode = $this->TdcsConfigure->isUnitTestMode();
		
		// If system is in unit test mod recieve the current time of day from GET parameter
		if ($unitTestMode) {
			if (isset($this->params['url']['test_tod'])) {
				$currentTimeOfDay = $this->params['url']['test_tod'];
				if(!$this->isValidTime($currentTimeOfDay)){
					$this->allowCommit = false;
			//		$this->Session->setFlash('Unit Test mode. Please provide a valid test time of day in hhmm format.', 'message_error');
			//		$this->render('../webservices/index', 'nomenu');		
					echo "Unit Test mode. Please provide a valid test time of day in hhmm format.\n";
					exit(0);	
				}
			} else {
				$this->allowCommit = false;
			//	$this->Session->setFlash('Unit Test mode. Please provide a valid test time of day in hhmm format.', 'message_error');
			//	$this->render('../webservices/index', 'nomenu');		
				echo "Unit Test mode. Please provide a valid test time of day in hhmm format.\n";
				exit(0);
			}
		} else {
			if(isset($this->params['url']['test_tod'])){
				$this->allowCommit = false;
			//	$this->Session->setFlash('Not in Unit Test mode. Please remove any unnecessary GET parameters.', 'message_error');
			//	$this->render('../webservices/index', 'nomenu');		
				echo "Not in Unit Test mode. Please remove any unnecessary GET parameters.\n";
				exit(0);
			}
	    	$currentTimeOfDay = date("Hi",time());
		}
    
    
		//Dummy ETag for compatibility with bloggate, since bloggate code is generic and needs ETag
		header("ETag: 0");
	
		while(1) {
			
			// Get last processed tid
			$this->LastProcessedTid->recursive = 0;
			$lastProcessedTids = $this->LastProcessedTid->findAll();
			if (empty($lastProcessedTids) || count($lastProcessedTids)==0) {
				$lastProcessedTid_id   = 1;
				$lastProcessedTid_tuid = 0;
			} else {
				$lastProcessedTid_id   = $lastProcessedTids[0]['LastProcessedTid']['id'];
				$lastProcessedTid_tuid = $lastProcessedTids[0]['LastProcessedTid']['tu_id'];
			}
			// Search in round-robin manner with search limit as last process tid value
			$responce = "";
			$this->TelematicUnit->recursive = 1;
			$telematicUnits = $this->TelematicUnit->findAll(array('TelematicUnit.telematic_unit_location_type'=>'H','TelematicUnitType.telematic_unit_type_code'=>'tgate', "TelematicUnit.id >$lastProcessedTid_tuid"));
			if (empty($telematicUnits) || count($telematicUnits) == 0) {
				// no TIDs exist, so nothing needs to be done
				if ($lastProcessedTid_tuid == 0) {
					header("HTTP/1.1 404 Not Found");
					echo "No TID Information Exists\n";	
					exit(0);
				} else {
					// we've reached the end of TU table. So, we reset the last_tid to zero
					unset($this->data);
					$this->data['id']    = $lastProcessedTid_id;	
					$this->data['tu_id'] = 0;	
					$this->LastProcessedTid->save($this->data);
					// Try to get fist TID from table
					$telematicUnits = $this->TelematicUnit->findAll(array('TelematicUnit.telematic_unit_location_type'=>'H','TelematicUnitType.telematic_unit_type_code'=>'tgate'));
					if (empty($telematicUnits) || count($telematicUnits) == 0) {
						header("HTTP/1.1 404 Not Found");
						echo "No TID Information Exists\n";	
						exit(0);
					}
				}
			} 
				
			// Got a TDU to which we have to send vehicle timing information
			$telematicUnitId            = $telematicUnits[0]['TelematicUnit']['id'];
			$telematicUnitCode          = $telematicUnits[0]['TelematicUnit']['telematic_unit_code'];
			$telematicUnitHotzoneId     = $telematicUnits[0]['TelematicUnit']['hotzone_id'];
			$telematicUnitHotzoneNodeId = $telematicUnits[0]['Hotzone']['node_id'];
			
			// Find all vehicles which are going to arrive at the node where the curr_tid is located.
			$vehicleScheduleList = $this->getVehicleScheduleList($telematicUnitHotzoneNodeId, $currentTimeOfDay);
	//	debug($vehicleScheduleList);
			
			// Find out their delays and compute their expected arrival time at the curr_tid's node.
			$vehicleScheduleList = $this->getExpectedArrivalTime($vehicleScheduleList, $currentTimeOfDay);
	//	debug($vehicleScheduleList);
			
			// Format a line for each vehicle and compose multi-line message
			$display = $this->formatMultilineDisplay($vehicleScheduleList);
	//	debug($display);
			
			//Here create if not already there, make a folder with name as tid_info in /var/tmp
			//In this folder save the last generated display for each tu_code as tu_code.lastDisplay
			//This file gets modified if the display generated now is different than this one
			//If the two contents are same, do not set header and neither echo the display
			$tidInfoFolder = TMP."/tid_info";
			
	        if (!is_dir($tidInfoFolder)) {
				mkdir($tidInfoFolder,  0777);
				chmod($tidInfoFolder,  0777);
			}
			
			$generateDisplay = true;	//by default
			$telematicUnitCodeDisplayFile = $tidInfoFolder."/".$telematicUnitCode.".lastDisplay";
			if (file_exists($telematicUnitCodeDisplayFile)) {
				//read the contents and compare it with newly generated contents
				$previousDisplay = file_get_contents($telematicUnitCodeDisplayFile);
				if (strcmp(trim($previousDisplay), trim($display))==0) {//same display, so ignore it
					//If same set the flag to not generate display 
					$generateDisplay = false;
				}
			}
			if ($generateDisplay) {
				file_put_contents($telematicUnitCodeDisplayFile, $display);// replace the contents of the file with the new contents
				chmod($telematicUnitCodeDisplayFile, 0777);
			}
				// Set X-TU-List with the Code of TDU to which we have to send vehicle timing information 
				header("X-TU-List:" . $telematicUnitCode);
			
			//Store curr_tid in last_tid table	
			unset($this->data);
			$this->data['id']    = 1;	
			$this->data['tu_id'] = $telematicUnitId;
			$this->LastProcessedTid->save($this->data);
			break;
			
			  	
		}// End of While loop
				
		// Render output
		/*
		if($generateDisplay){
			$this->set('responce', $display);
		}
		$this->render('../webservices/index', 'webservice');
		*/
		
		// Since there is no explicit render function call and we are not loggedin user will be redirected to login screen
		// So afterFilter will not be called automatically 
		$this->afterFilter();
		
		echo $display;
		exit();
		
    }
	
	function getVehicleScheduleList($telematicUnitHotzoneNodeId, $currentTimeOfDay) {
		
		// Find out current day-of-week (curr_dow).
		$weekDays = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat');
		$currentDayOfWeek = strtolower(date('D'));
		foreach ($weekDays as $key=>$value) {
			if ($currentDayOfWeek == $value) {
		    	$currentDayOfWeek_Number = $key+1;
				break;
			}	
		}
		
		// Get value for configurable parameter tid_time_limit
		$tid_time_limit = $this->TdcsConfigure->getTidTimeLimit();
		
		
		// find all route schedule node assoc entries
		// find all route scheules which uses this node
		$this->RouteScheduleNodeAssoc->recursive = 1;
		unset($conditions);
		unset($fields);
		$conditions = array("RouteScheduleNodeAssoc.node_id"=>$telematicUnitHotzoneNodeId, "(TimeSchedule.time_schedule_arrival_day=-1 OR TimeSchedule.time_schedule_arrival_day=$currentDayOfWeek_Number)");
		$fields = array('DISTINCT RouteScheduleNodeAssoc.route_schedule_id'); 
		$routeSchedules = $this->TimeSchedule->findAll($conditions, $fields);
		foreach ($routeSchedules as $routeSchedule) {
			$routeScheduleIdArray[] = $routeSchedule['RouteScheduleNodeAssoc']['route_schedule_id'];
		}
		unset($conditions);
		unset($fields);
		if (empty($routeScheduleIdArray)) {
			$conditions = array("Trip.route_schedule_id IN (0)");
		} else {
			$routeScheduleIdString = implode(",", $routeScheduleIdArray);	
			$conditions = array("Trip.route_schedule_id IN ($routeScheduleIdString)");
		}
		
		// Find all vehicles which are going to arrive at the node where the curr_tid is located 
		$this->Trip->recursive = 2;
		$conditions["Trip.trip_status"] = "S";
		$fields = array('DISTINCT Trip.vehicle_id', 'Trip.route_schedule_id'); 
		$trips = $this->Trip->findAll($conditions, $fields);
		if (count($trips) > 0) {
			foreach ($trips as $trip) {
				unset($temp);
				$temp['vehicle_id'] = $trip['Trip']['vehicle_id'];
				$temp['schedule_id'] = $trip['Trip']['route_schedule_id'];
				$temp['hz_node_id'] = $telematicUnitHotzoneNodeId;
				//$temp['tod']        = $this->TimeSchedule->field("Nodeschedule.nodeschedule_timeofday", array("Nodeschedule.routeschedule_id"=>$trip['Trip']['routeschedule_id'], "Nodeschedule.node_id"=>$telematicUnitHotzoneNodeId));
				$temp['tod']        = $this->TimeSchedule->field("TimeSchedule.time_schedule_arrival_time", array("RouteScheduleNodeAssoc.route_schedule_id"=>$trip['Trip']['route_schedule_id'], "RouteScheduleNodeAssoc.node_id"=>$telematicUnitHotzoneNodeId));
				$temp['category']   = $trip['Vehicle']['VehicleCategory']['vehicle_category_code'];
				$temp['route_code'] = $trip['RouteSchedule']['Route']['route_code'];
				$vehicleScheduleList[] = $temp;  
			}
			return $vehicleScheduleList;
		} else {
			return array();
		}
		  
	}
	
	function getExpectedArrivalTime($vehicleScheduleList, $currentTimeOfDay) {
		
		foreach ($vehicleScheduleList as $key => $vehicleScheduleListItem) {
			$vehicleCurrentNode = $this->VehicleCurrentNode->find(array('vehicle_id'=>$vehicleScheduleListItem['vehicle_id']), NULL, "vehicle_current_node_arrival_timestamp DESC");
			if(!is_array($vehicleCurrentNode) || count($vehicleCurrentNode)==0){
				// No entries in the vehicle-current-nodes table for the current vehicle
				continue;
			}
			
			$vehicle_arrival_timestamp = $vehicleCurrentNode['VehicleCurrentNode']['vehicle_current_node_arrival_timestamp'];
	//	debug("$vehicle_arrival_timestamp:$vehicle_arrival_timestamp");
			$vehicle_arrival_time = $vehicle_arrival_timestamp[11].$vehicle_arrival_timestamp[12].$vehicle_arrival_timestamp[14].$vehicle_arrival_timestamp[15];
	//	debug("vehicle_arrival_time:$vehicle_arrival_time");

			//Get time of day for the tid node
			$vehicle_tid_node_timeofday = $vehicleScheduleListItem['tod'];
	//	debug("vehicle_tid_node_timeofday:$vehicle_tid_node_timeofday");
			
			//Get time of day for current node
			//$current_node_timeofday  = $this->Nodeschedule->field("Nodeschedule.nodeschedule_timeofday", array("Nodeschedule.routeschedule_id"=>$vehicleScheduleListItem['shedule_id'], "Nodeschedule.node_id"=>$vehicleCurrentNode['Vehiclecurrentnode']['node_id']));
			$current_node_timeofday  = $this->TimeSchedule->field("TimeSchedule.time_schedule_arrival_time", array("RouteScheduleNodeAssoc.route_schedule_id"=>$vehicleScheduleListItem['schedule_id'], "RouteScheduleNodeAssoc.node_id"=>$vehicleCurrentNode['VehicleCurrentNode']['node_id']));
			if (!$current_node_timeofday) {
				break;
			}
	//	debug("current_node_timeofday:$current_node_timeofday");
			$current_node_timeofday = $current_node_timeofday[0].$current_node_timeofday[1].$current_node_timeofday[3].$current_node_timeofday[4];
	//	debug("current_node_timeofday:$current_node_timeofday");
			
	//	debug("vehicle_arrival_time:$vehicle_arrival_time");
			// Get Time difference
			//$timeDifference = $this->timeDifferenceInSeconds($vehicle_arrival_time, $current_node_timeofday);
			$timeDifference = $this->timeDifferenceInSeconds($vehicle_arrival_time, $current_node_timeofday);
	//	debug("timeDifference:$timeDifference");
			
			/*
			Tsched = scheduled_travel_time from current_node to tid_node
			Tarrival = Arrival time for current_node
			Tlast_update = Last update time for current node
			Tstop_over_delay = Tlast_update - Tarrival - scheduled_stop_over_time
			Texpected_arrival_time at tid_node = Tarrival + Tsched + Tstop_over_delay
			*/
			/*
			$T_sched = $this->timeDifferenceInSeconds($vehicle_tid_node_timeofday, $current_node_timeofday);//TSched
			$p_T_sched = $T_sched/60;
			/////echo "T_sched = ".$p_T_sched."<BR>";
			if($T_sched < 0){
				continue;
			}
			*/
			if($timeDifference < 0){
				continue;
			}
			
			$Tarrival     = $vehicleCurrentNode['VehicleCurrentNode']['vehicle_current_node_arrival_timestamp'];
			
			$Tlast_update = $vehicleCurrentNode['VehicleCurrentNode']['vehicle_current_node_lastupdate_timestamp'];
			
			// Get value for configurable parameter stop_over_time, by default it is 10 minutes
			$stop_over_time    = $this->TdcsConfigure->getStopOverTime();
			
			$t_stop_over_time  = $stop_over_time/60;
			
			$Tstop_over_delay = strtotime($Tlast_update) - strtotime($Tarrival) - $stop_over_time;
			$p_Tstop_over_delay  = $Tstop_over_delay/60;
			if ($Tstop_over_delay < 0){
				$Tstop_over_delay = 0;
			}
	//	debug("Tstop_over_delay:$Tstop_over_delay");
	//	debug("vehicle_tid_node_timeofday: ".($vehicle_tid_node_timeofday));
	//	debug("vehicle_tid_node_timeofday: ".strtotime($vehicle_tid_node_timeofday));
			//$Texpected_arrival_time = strtotime($Tarrival) + $T_sched + $Tstop_over_delay;
			$Texpected_arrival_time = strtotime($vehicle_tid_node_timeofday) + $timeDifference + $Tstop_over_delay;
			
	//	debug("Texpected_arrival_time:$Texpected_arrival_time");
			
			//convert it back to timestamp and extract the hour and minute part out of it
			$t_eat = date("Hi",$Texpected_arrival_time);
	//	debug("expected_time:$t_eat");
	//	debug("currentTimeOfDay:$currentTimeOfDay");
			
			// echo "Time Diff between Texpected_arrival_time timeofday and current time of day: ".timeDifferenceInSeconds($t_eat,$curr_tod)."<P>";
			if($this->timeDifferenceInSeconds($t_eat, $currentTimeOfDay)>=0){//If EAT is later than current time
				$vehicleScheduleList[$key]['expected_time'] = $t_eat;
				$vehicleScheduleList[$key]['expiry_time'] = $Texpected_arrival_time;
			}
			
		}
		return $vehicleScheduleList;
		
	}
	
	function formatMultilineDisplay($vehicleScheduleList){
		
		$display = "";
		$newLine = "\n";
		$display = "|Key|Expiry Time|Vehicle Type|From|To|Via Node|Arrival Time|".$newLine;
		foreach ($vehicleScheduleList as $key => $vehicleScheduleListItem) {
			if (array_key_exists('expected_time', $vehicleScheduleListItem)) {
				$vehicle_type     = $vehicleScheduleListItem['category'];
				$expected_time    = $vehicleScheduleListItem['expected_time'];
				$expiry_time      = $vehicleScheduleListItem['expiry_time'];
			} else { 
				continue;
			}
			$vehicle_type = strtoupper($vehicle_type);
			$ivtuCode = $this->TelematicUnit->field('TelematicUnit.telematic_unit_code', array('TelematicUnit.vehicle_id'=>$vehicleScheduleListItem['vehicle_id'], 'TelematicUnitType.telematic_unit_type_code'=>'ivtu')); 
			$ivtuCode = ($ivtuCode) ?  $ivtuCode : "-"; 
			$this->RouteSchedule->recursive = 3;
			$route = $this->RouteSchedule->find(array('RouteSchedule.id'=>$vehicleScheduleListItem['schedule_id']));
			if ($route['Route']['node_id']) {
				$start_node         = $route['Route']['RouteNodeAssoc'][0]['Node']['node_code'];
				$lastNodeSequenceNo = count($route['Route']['RouteNodeAssoc']) -1; 
				$dest_node          = $route['Route']['RouteNodeAssoc'][$lastNodeSequenceNo]['Node']['node_code']; 
				$via_node           = $route['Route']['Node']['node_code']; 
				$start_node         = strtoupper($start_node);
				$dest_node          = strtoupper($dest_node);
				$via_node           = strtoupper($via_node);
				//$display .= $expiry_time.":".$vehicle_type." from ".$start_node." to ".$dest_node." Via ".$via_node." Arriving at ".$expected_time." Hrs".$newLine;
				$display .= "|".$ivtuCode."|".$expiry_time."|".$vehicle_type."|".$start_node."|".$dest_node."|".$via_node."|".$expected_time." Hrs".$newLine;
				
			} else {
				$start_node         = $route['Route']['RouteNodeAssoc'][0]['Node']['node_code'];
				$lastNodeSequenceNo = count($route['Route']['RouteNodeAssoc']) -1; 
				$dest_node          = $route['Route']['RouteNodeAssoc'][$lastNodeSequenceNo]['Node']['node_code'];
				$start_node         = strtoupper($start_node);
				$dest_node          = strtoupper($dest_node); 
			//	$display .= $expiry_time.":".$vehicle_type." from ".$start_node." to ".$dest_node." Arriving at ".$expected_time." Hrs".$newLine;
				$display .= "|".$ivtuCode."|".$expiry_time."|".$vehicle_type."|".$start_node."|".$dest_node."|-|".$expected_time." Hrs".$newLine;
			}
		}
		//return strtoupper($display);
		return ($display);
		
	}
	
	function timeDifferenceInSeconds($end_time, $start_time){//times are in HHMM format
		
		$temp_timestamp = date("Y-m-d H:i:s",time());
		//replace the hour and minute part with $scheduled_time's hour and minute part
		$start_time_timestamp = $temp_timestamp;
		$end_time_timestamp   = $temp_timestamp;
		
		//replacing hour part
		$start_time_timestamp[11]=$start_time[0];
		$start_time_timestamp[12]=$start_time[1];
		//replacing minute part
		$start_time_timestamp[14]=$start_time[2];
		$start_time_timestamp[15]=$start_time[3];
		
		//replacing hour part
		$end_time_timestamp[11]=$end_time[0];
		$end_time_timestamp[12]=$end_time[1];
		//replacing minute part
		$end_time_timestamp[14]=$end_time[2];
		$end_time_timestamp[15]=$end_time[3];
			
		//change it to time by strtotime
		$diff = strtotime($end_time_timestamp)-strtotime($start_time_timestamp);//difference in seconds
		return $diff;
		
	}
	
	function isValidTime($time){
		
		if(ereg('[^0-9]', $time) || strlen($time)!=4){
			return false;
		} else {
			$hh = (int) ($time/100);
			$mm = $time - $hh*100;
			if($hh>=24 || $hh<0 || $mm>=60 || $mm<0){
				return false;
			}  
		}
		return true;
		
	}
}
?>